package com.sxf.auth.login.service;

import cn.hutool.core.util.ObjectUtil;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.sxf.auth.enums.*;
import com.sxf.auth.login.model.AuthUser;
import com.sxf.auth.login.vo.*;
import com.sxf.biz.customer.service.CustomerService;
import com.sxf.biz.customer.vo.StaffInfoDetaiVo;
import com.sxf.biz.model.Customer;
import com.sxf.cache.CacheUtil;
import com.sxf.cache.EhcacheElementType;
import com.sxf.common.enums.ErrorCodeEnum;
import com.sxf.common.exceptions.BusinessException;
import com.sxf.consts.YtConsts;
import com.sxf.core.aspect.UserThreadLocal;
import com.sxf.utils.JwtTokenUtil;
import com.sxf.utils.YtUtil;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;
//import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.StringUtils;

import java.util.*;

/**
 * @author villain
 * 登录
 */
@Service
public class LoginService {

    @Autowired
    private UserService userService;

    @Autowired
    private SmsService smsService;
    @Autowired
    private CustomerService customerService;

    @Autowired
    private JwtTokenUtil jwtTokenUtil;
    @Autowired
    CacheUtil cacheUtil;

    @Value("${user.lockTime:30}")
    private long lockTime;

    @Value("${user.needCheckNum:4}")
    private int needCheckNum;

    @Value("${user.lockNum:8}")
    private int lockNum;

    public static final String SEND_CODE_PREFIX = "SEND_CODE:";

    /**
     * 登录
     *
     * @param loginDTO
     * @return
     */
    public LoginRes login(LoginReq loginDTO) {

//        String key = checkErrorTimes(loginDTO);

//        Object fail = redisClient.get(key);
//        int failNum = fail == null ? 0 : (int) fail;
        LambdaQueryWrapper<AuthUser> queryWrapper = new LambdaQueryWrapper<>();
        if (LoginTypeEnum.ACCOUNT.getCode().equals(loginDTO.getLoginType())) {
            if(StringUtils.isEmpty(loginDTO.getAccount())){
                throw new BusinessException("账号不能为空");
            }
            queryWrapper.eq(AuthUser::getAccount,loginDTO.getAccount());
        }else{
            if(StringUtils.isEmpty(loginDTO.getUserMobile())){
                throw new BusinessException("手机号不能为空");
            }
            queryWrapper.eq(AuthUser::getUserMobile,loginDTO.getUserMobile())
                    .eq(AuthUser::getUserType,UserTypeEnum.SUBJECTS.getCode())
                    .eq(AuthUser::getStatus,UserStatusEnum.VALID.getCode());
        }

        AuthUser authUser = userService.getOne(queryWrapper);
        //只校验账户登陆，手机号登陆如果不存在，则认为是自动注册，走下面的自动注册+登陆逻辑
        if (ObjectUtil.isNull(authUser) && LoginTypeEnum.ACCOUNT.getCode().equals(loginDTO.getLoginType())) {
            throw new BusinessException(ErrorCodeEnum.USER_PASSWORD_ERROR);
        }

        // 用户名密码登录
        if (LoginTypeEnum.ACCOUNT.getCode().equals(loginDTO.getLoginType())) {
            if (!authUser.getPassword().equals(YtUtil.sha256(authUser.getSalt(), loginDTO.getCheckCode()))) {
                //密码错误
//                if (fail == null) {
//                    //失败错误为0
//                    redisClient.set(key, 1, DateUtils.getSecondsNextEarlyMorning());
//                } else {
//                    //累加错误次数（该账户同时使用同一客户端登录有可能导致计数不准确，该需求非强一致性）
//                    failNum = failNum + 1;
//                    //如果错误次数未到锁定次数，超时时间为当天晚上00：00，到锁定次数锁定lockTime分钟
//                    redisClient.set(key, failNum, failNum >= lockNum ? lockTime * 60 : DateUtils.getSecondsNextEarlyMorning());
//                    if (failNum >= needCheckNum && failNum < lockNum) {
//                        throw new BusinessException(ErrorCodeEnum.ERROR_MULTI_PASSWORD, "账号或者密码错误，今日还可尝试" + (lockNum - failNum) + "次");
//                    } else if (failNum >= lockNum) {
//                        throw new BusinessException(ErrorCodeEnum.FORBIDDEN_ACCOUNT, lockNum, lockTime);
//                    }
//                }
                throw new BusinessException(ErrorCodeEnum.USER_PASSWORD_ERROR);
            }
//            else {
//                redisClient.del(key);
//            }
        } else if (LoginTypeEnum.MOBILE.getCode().equals(loginDTO.getLoginType())) {
            ValidateSmsCodeReq req = new ValidateSmsCodeReq();
            req.setCode(loginDTO.getCheckCode());
            req.setUserMobile(loginDTO.getUserMobile());
            req.setSmsType(SmsTypeEnum.SENDCODE_LOGIN.getCode());
            smsService.validate(req);

            //自动注册
            if(ObjectUtil.isNull(authUser)){
                RegisterReq registerReq = new RegisterReq();
                registerReq.setUserMobile(loginDTO.getUserMobile());
                registerReq.setUserType(UserTypeEnum.SUBJECTS.getCode());
                authUser = autoRegister(registerReq);
            }
        }

        // 如果用户状态不正常，拦住！
        if (CommonStatusEnum.INVALID.getCode().equals(authUser.getStatus())) {
            throw new BusinessException(ErrorCodeEnum.USER_FREEZE_ERROR);
        }

        if (!loginDTO.getUserType().equals(authUser.getUserType())) {
            throw new BusinessException(ErrorCodeEnum.LOGIN_PLAT_ERROR);
        }

        LoginRes loginRes = new LoginRes();
        loginRes.setPkUser(authUser.getPkUser());
        loginRes.setUserMobile(authUser.getUserMobile());
        loginRes.setIdNo(authUser.getIdNo());
        loginRes.setUserName(authUser.getUserName());
        loginRes.setUserType(authUser.getUserType());
        loginRes.setAccount(authUser.getAccount());
        if(UserTypeEnum.CUSTOMER.getCode().equals(loginDTO.getUserType())){
            Customer customer = customerService.getOne(new QueryWrapper<Customer>().lambda().eq(Customer::getPkAdmin, authUser.getPkUser())
                    .last("limit 1"));
            if(customer == null){
                throw new BusinessException(ErrorCodeEnum.CUSTOMER_NOT_EXIST_ERROR);
            }
            loginRes.setCustomerName(customer.getCustomerName());
            loginRes.setCustomerAlias(customer.getCustomerAlias());
        }
        /**
         * 一个协调员可能属于多个客户
         */
        if(UserTypeEnum.COORDINATE.getCode().equals(loginDTO.getUserType())){
            List<StaffInfoDetaiVo> staffInfoByPkUser = customerService.getStaffInfoByPkUser(loginRes.getPkUser());
            if(staffInfoByPkUser != null && staffInfoByPkUser.size() > 0){
                loginRes.setStaffType(staffInfoByPkUser.get(0).getStaffType());
                loginRes.setCustomerName(staffInfoByPkUser.get(0).getCustomerName());
                loginRes.setCustomerAlias(staffInfoByPkUser.get(0).getCustomerAlias());
                loginRes.setSmoName(staffInfoByPkUser.get(0).getSmoName());
            }
        }

        Map<String, Object> claims = new HashMap<String, Object>();
        claims.put("account", LoginTypeEnum.MOBILE.getCode().equals(loginDTO.getLoginType())? authUser.getUserMobile():authUser.getAccount());
        claims.put("userName", authUser.getUserName());
        String token = jwtTokenUtil.generateToken(claims);
        loginRes.setToken(token);

        cacheUtil.set(EhcacheElementType.TOKEN,YtConsts.USER_TOKEN_KEY + token, loginRes);

        return loginRes;
    }

    public Boolean forgetPwd(ForgetPwdReq forgetPwdReq){
        ValidateSmsCodeReq req = new ValidateSmsCodeReq();
        req.setCode(forgetPwdReq.getCheckCode());
        req.setUserMobile(forgetPwdReq.getUserMobile());
        req.setSmsType(SmsTypeEnum.FORGET_PASSWORD.getCode());
        smsService.validate(req);

        QueryWrapper<AuthUser> queryWrapper = new QueryWrapper<>();
        queryWrapper.lambda().eq(AuthUser::getUserMobile,forgetPwdReq.getUserMobile())
                .eq(AuthUser::getUserType,UserTypeEnum.COORDINATE.getCode())
                .eq(AuthUser::getStatus,UserStatusEnum.VALID.getCode())
                .last("limit 1");
        AuthUser user = userService.getOne(queryWrapper);
        if(user == null){
            throw new BusinessException(ErrorCodeEnum.USER_NOT_EXIST_ERROR);
        }

        String salt = YtUtil.getSalt();
        String password = YtUtil.sha256(salt, forgetPwdReq.getNewPassword());
        user.setSalt(salt);
        user.setPassword(password);
        user.setModifiedTime(new Date());
        user.setModifier(user.getPkUser());
        return userService.updateById(user);
    }

//    private String checkErrorTimes(LoginReq loginDTO) {
//
//        // 校验错误次数
//        String key = PASSWORD_FAIL_NUM + loginDTO.getPhoneNo();
//        Object fail = redisClient.get(key);
//        int failNum = fail == null ? 0 : (int) fail;
//        if (failNum >= lockNum) {
//            //账户被锁定
//            long time = redisClient.getExpire(key);
//            throw new BusinessException(ErrorCodeEnum.FORBIDDEN_ACCOUNT, lockNum, (int) Math.ceil(time / 1000.0 / 60));
//        }
//
//        // 验证码登录不校验图形验证码
//        if (LoginTypeEnum.PASSWORD.getCode().equals(loginDTO.getLoginType())) {
//
//            //需要输入图形验证码
//            if (failNum >= needCheckNum) {
//                if (StringUtils.isEmpty(loginDTO.getMoveLength()) || StringUtils.isEmpty(loginDTO.getKey())) {
//                    throw new BusinessException(ErrorCodeEnum.ERROR_MULTI_PASSWORD, "密码错误超过" + needCheckNum + "次,请输入验证码");
//                }
//                imageVerifyCodeService.verifyImageCode(loginDTO.getMoveLength(), loginDTO.getKey(), true);
//            }
//        }
//
//        return key;
//    }


    public void logout() {
        String token = UserThreadLocal.get().getToken();
        cacheUtil.delete(EhcacheElementType.TOKEN,YtConsts.USER_TOKEN_KEY + token);
    }

//    /**
//     *
//     * @param registerReq
//     */
//    @Transactional(rollbackFor = Exception.class)
//    public AuthUser register(RegisterReq registerReq) {
//        AutoRegisterReq autoRegisterReq = new AutoRegisterReq();
//        autoRegisterReq.setUserMobile(registerReq.getUserMobile());
//        autoRegisterReq.setPassword(registerReq.getPassword());
//
//        AuthUser user = autoRegister(autoRegisterReq, UserTypeEnum.SUBJECTS);
//        return user;
//    }

    public AuthUser autoRegister(RegisterReq autoRegisterReq) {
        // 密码-盐
        String salt = YtUtil.getSalt();
        AuthUser au = new AuthUser();
        au.setPkUser(YtUtil.getUuid());
        au.setUserMobile(autoRegisterReq.getUserMobile());
        au.setAccount("");
        au.setPassword(YtUtil.sha256(salt, autoRegisterReq.getPassword()));
        au.setCreatedTime(new Date());
        au.setModifiedTime(null);
        au.setRemark(null);
        au.setSalt(salt);
        au.setStatus(UserStatusEnum.VALID.getCode());
        au.setUserType(autoRegisterReq.getUserType());
//        au.setCreator(autoRegisterReq.getCreator());
//        au.setCreatorName(autoRegisterReq.getCreatorName());
        userService.save(au);
        return au;
    }
}